/*
 * FE_SemanticClass.java
 *
 * Created on APR 28, 2010
 * Semantic Class Agreement Feature
 *
 * author: chuter
 * mail: lliu@ir.hit.edu.cn
 */

package edu.hit.irlab.coref.features.pair;

import java.util.List;

import nlpeap.knowledge.SemanticClass;
import nlpeap.knowledge.SemanticClass.SemanticClassEnum;
import nlpeap.ml.FeatureType;
import nlpeap.ml.TriValue;
import nlpeap.ml.FeatureDescription;

import edu.hit.irlab.coref.PairFeatureExtractor;
import edu.hit.irlab.coref.PairInstance;
import edu.hit.irlab.coref.mentionfinder.Mention;
/**
 * Semantic Class Agreement Feature(Soon. 2001).<br> 
 * Either True/False or Unknown.
 *
 * @author chuter
 */
public class FE_SemanticClass  implements PairFeatureExtractor{
    
	private static final SemanticClass _sm_ins = SemanticClass.getInstance();
	
    public static final FeatureDescription<TriValue> FD_IS_SEMANTIC_CLASS=
        new FeatureDescription<TriValue>(
        		FeatureType.FT_NOMINAL_ENUM, 
        		TriValue.class, 
        		"SemanticClass_Agreement"
        	);
    
    /** Creates a new instance of FE_SemanticClass */
    public FE_SemanticClass() {
    }
    
    public void describeFeatures(List<FeatureDescription> fds) 
    { fds.add(FD_IS_SEMANTIC_CLASS); }
 
    /** whether the two mentions are both ProperName, and
     *  their types are match */
    private static boolean isProperNameMatch(Mention _antecedent, Mention _anaphor)
    {
    	if (_anaphor.getProperName() && _antecedent.getProperName()) { 
    		if (_anaphor.getMentionSubType()!= null && _anaphor.
    				getMentionSubType().equals(_antecedent.getMentionSubType()))
    		{ return true; }
    	}
    	return false;
    }
    
    /** at least one of the two mentions is a Pronoun,
     *  then check if they are match  */
    private static boolean oneProNounMatch(Mention _antecedent, Mention _anaphor)
    {
    	//if the anaphor is a person pronoun, then the antecedent must
    	//be a person name
    	if (_anaphor.getPerProNoun() && _antecedent.getPersonName())
    		return true;
    	
    	//then the anaphor is Demonstrative(starts with "this" or "that"), 
    	//then the antecedent must be a proper name, and their SubType 
    	//must be matched
    	if ((_anaphor.getDemNoun() || _anaphor.getDemNominal()) 
    			&& _antecedent.getProperName()) {
    		String _ana_subType = _anaphor.getMentionSubType();
    		String _ant_subType = _antecedent.getMentionSubType();
    		if (_ana_subType!=null && _ant_subType!=null 
    				&& _ana_subType.equals(_ant_subType))
    			return true;
    	}
    	    			
    	return false;
    }
    
    public void extractFeatures(PairInstance inst) 
    { inst.setFeature(FD_IS_SEMANTIC_CLASS, getSemanticClassMatchFE(inst)); }
    
    public static TriValue getSemanticClassMatchFE(PairInstance inst)
    {	
    	Mention _anaphor = inst.getAnaphor();
    	Mention _antecedent = inst.getAntecedent();
    	//if the two mentions are both ProperNames
    	if (isProperNameMatch(_antecedent, _anaphor)) 
    		return TriValue.TRUE;
    	
    	if (oneProNounMatch(_anaphor, _antecedent) 
    			|| oneProNounMatch(_antecedent, _anaphor)) 
    	{ return TriValue.TRUE; }
    		
    	//otherwise, check the semantic classes from the HowNet
    	//for the two mentions
    	if (
    			_anaphor.getSemanticClass().equals(SemanticClassEnum.UNKNOWN)
    		||
    			_antecedent.getSemanticClass().equals(SemanticClassEnum.UNKNOWN)
    	)
    	{ return TriValue.UNKNOW; }
	    	
    	String[][] _ana_sementic_class_arr = _sm_ins.getSemanticStrings(_anaphor.getHead());
    	String[][] _ant_sementic_class_arr = _sm_ins.getSemanticStrings(_antecedent.getHead());
    	for (String[] _ana_sm_class : _ana_sementic_class_arr) {
    		for (String[] _ant_sm_class : _ant_sementic_class_arr) {
    			if (
    					_ana_sm_class[0].equals(_ant_sm_class[0])
    				||
    					_ana_sm_class[0].equals(_ant_sm_class[1])
    				||
    					_ana_sm_class[1].equals(_ant_sm_class[0])
    				||
    					_ana_sm_class[1].equals(_ant_sm_class[1])
    			)
    			{ return TriValue.TRUE; }
    		}
    	}
    	
    	return TriValue.FALSE;
    }
    
}
